%%%-------------------------------------------------------------------
%%% @author Anil Kumar S. R. <anil.kumar@geodesic.com>
%%% @copyright (C) 2010, 
%%% @doc
%%%
%%% @end
%%% Created : 25 Aug 2010 by Anil Kumar S. R. <anil.kumar@geodesic.com>
%%%-------------------------------------------------------------------
-module(stun).
-export([binding_request/3, parse_response/1]).
-include("stun_header.hrl").

-record(attributes, {mapped_address, xor_mapped_address}).

binding_request(Server_Address, Server_Port, Socket) ->
	Header = stun_packet:generate_header(?MT_BINDING_REQUEST, 0),
	Request_Message = Header,

	gen_udp:send(Socket, Server_Address, Server_Port, Request_Message).

parse_response(Response) ->
	<<Message_Type:16, Message_Length:16, Transaction_ID:128, Rest/binary>> = Response,
    Message_Length_Bits = Message_Length * 8,
    <<Message:Message_Length_Bits, _/binary>> = Rest,
	Attributes = get_attributes(#attributes{}, <<Transaction_ID:128>>, <<Message:Message_Length_Bits>>),
	case Message_Type of 
		?MT_BINDING_RESPONSE ->
			if
				Attributes#attributes.xor_mapped_address == undefined ->
					{binding_response, Attributes#attributes.mapped_address};
				true ->
					{binding_response, Attributes#attributes.xor_mapped_address}
			end;
		?MT_BINDING_ERROR_RESPONSE ->
			binding_error_response;
		_ ->
			unknown_response
	end.

get_attributes(Attributes, _, <<>>) ->
	Attributes;

get_attributes(Attributes, Transaction_ID, Message) ->
	<<Type:16, Length:16, Rest/binary>> = Message,
    Length_Bits = Length * 8,
    <<Value:Length_Bits, Rest_Message/binary>> = Rest,
	case Type of 
		?ATR_MAPPED_ADDRESS ->
			<<_:8, _:8, Port:16, First_Octet:8, Second_Octet:8, Third_Octet:8, Fourth_Octet:8>> = <<Value:Length_Bits>>,
			get_attributes(Attributes#attributes{mapped_address = {inet_parse:ntoa({First_Octet, Second_Octet, Third_Octet, Fourth_Octet}), Port}},
                           Transaction_ID, Rest_Message);
		?ATR_XOR_MAPPED_ADDRESS ->
			<<_:8, _:8, Port:16, Address:32>> = <<Value:Length_Bits>>,
			<<Chopped_32_Transaction_ID:32, _/binary>> = Transaction_ID,
			<<Chopped_16_Transaction_ID:16, _/binary>> = Transaction_ID,
			XOR_Address = Chopped_32_Transaction_ID bxor Address,
			XOR_Port = Chopped_16_Transaction_ID bxor Port,
			[XOR_Hex_Address|_] = io_lib:format("~.16B", [XOR_Address]),
			First_Octet = erlang:list_to_integer(string:substr(XOR_Hex_Address, 1, 2), 16),
			Second_Octet = erlang:list_to_integer(string:substr(XOR_Hex_Address, 3, 2), 16),
			Third_Octet = erlang:list_to_integer(string:substr(XOR_Hex_Address, 5, 2), 16),
			Fourth_Octet = erlang:list_to_integer(string:substr(XOR_Hex_Address, 7, 2), 16),
			
			get_attributes(Attributes#attributes{xor_mapped_address = {inet_parse:ntoa({First_Octet, Second_Octet, Third_Octet, Fourth_Octet}), XOR_Port}},
                           Transaction_ID, Rest_Message);
		_ ->
			get_attributes(Attributes, Transaction_ID, Rest_Message)
	end.
